/* According to POSIX.1-2001, POSIX.1-2008 */
#include <sys/select.h>

/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        printf("usage:%s <dev>\n", argv[0]);
        return -1;
    }

    int fd = -1;
    fd_set read_fd_set;
    fd_set write_fd_set;
    int ret = -1;
    int nfds = 0;
    
    fd = open(argv[1], O_CLOEXEC | O_RDWR | O_NONBLOCK);
    if (fd < 0)
    {
        printf("open %s error(%s)\n", argv[1], strerror(errno));
        return -1;
    }

    while (1)
    {
        FD_ZERO(&read_fd_set);
        FD_ZERO(&write_fd_set);
        FD_SET(fd, &read_fd_set);
        FD_SET(fd, &write_fd_set);

        nfds = fd + 1;

        struct timeval timeout = {.tv_sec = 3, .tv_usec = 0};

        ret = select(nfds, &read_fd_set, &write_fd_set, NULL, &timeout);
        if (ret == -1)
        {
            printf("select error(%s)\n", strerror(errno));
            break;
        }
        else if (ret > 0)
        {
            for (int i = 0; i < ret; i++)
            {
#if 0
                if (FD_ISSET(fd, &read_fd_set))
                {
                    char buffer[2048] = {0};
                    ssize_t read_n = read(fd, buffer, sizeof(buffer));
                    if (read_n < 0)
                    {
                        printf("readable,read_n=%ld,error(%s)\n", read_n, strerror(errno));
                        break;
                    }
                    else if (read_n == 0)
                    {
                        printf("readable,read_n=%ld,error(%s)\n", read_n, strerror(errno));
                        break;
                    }
                    else
                    {
                        printf("readable,read_n=%ld,buffer=%s\n", read_n, buffer);
                    }
                }
#endif

#if 1
                if (FD_ISSET(fd, &write_fd_set))
                {
                    char buffer[1024] = {0};
                    struct timeval timestamp;

                    (void)gettimeofday(&timestamp, NULL);
                    (void)snprintf(buffer, 1024, "userspace-%s-%ld", __FILE__, timestamp.tv_sec * 1000 + timestamp.tv_usec / 1000);

                    ssize_t write_n = write(fd, buffer, strlen(buffer));
                    if (write_n < 0)
                    {
                        printf("writable,write_n=%ld,error(%s)\n", write_n, strerror(errno));
                    }
                    else if (write_n == 0)
                    {
                        printf("writable,write_n=%ld,error(%s)\n", write_n, strerror(errno));
                    }
                    else
                    {
                        printf("writable,write_n=%ld,buffer=%s\n", write_n, buffer);
                    }
                }
#endif
            }
        }
    
        sleep(timeout.tv_sec);
    }

    close(fd);

    return 0;
}